/*
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <http://www.gnu.org/licenses/>.
 */package org.merak.core.text.json;

import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Date;
import java.util.Enumeration;
import java.util.Map;

import org.merak.core.text.json.jsonfiers.ArrayJsonfier;
import org.merak.core.text.json.jsonfiers.CollectionJsonfier;
import org.merak.core.text.json.jsonfiers.DateJsonfier;
import org.merak.core.text.json.jsonfiers.EnumerationJsonfier;
import org.merak.core.text.json.jsonfiers.Jsonfier;
import org.merak.core.text.json.jsonfiers.MapJsonfier;
import org.merak.core.text.json.jsonfiers.NullJsonfier;
import org.merak.core.text.json.jsonfiers.ObjectJsonfier;
import org.merak.core.text.json.jsonfiers.PrimitiveJsonfier;
import org.merak.core.text.json.jsonfiers.StringJsonfier;

public class JsonfierSet {

	//~ Attributes ///////////////////////////////////////////////////////////////
	//****************************************************************************
	private Jsonfier nullJsonfier        = null;
	private Jsonfier primitiveJsonfier   = null;
	private Jsonfier enumJsonfier        = null;
	private Jsonfier stringJsonfier      = null;
	private Jsonfier dateJsonfier        = null;
	private Jsonfier objectJsonfier      = null;
	private Jsonfier arrayJsonfier       = null;
	private Jsonfier collectionJsonfier  = null;
	private Jsonfier mapJsonfier         = null;
	private Jsonfier enumerationJsonfier = null;

	//~ Constructors /////////////////////////////////////////////////////////////
	//****************************************************************************
	public JsonfierSet() {

		// Jsonfiers that doesn't need Stack Control
		this.nullJsonfier        = new NullJsonfier();
		this.primitiveJsonfier   = new PrimitiveJsonfier();
		this.enumJsonfier        = new StringJsonfier();
		this.stringJsonfier      = new StringJsonfier();
		this.dateJsonfier        = new DateJsonfier();
		// Jsonfiers that need Stack Control
		this.objectJsonfier      = new JsonfierControl( new ObjectJsonfier() );
		this.arrayJsonfier       = new JsonfierControl( new ArrayJsonfier() );
		this.collectionJsonfier  = new JsonfierControl( new CollectionJsonfier() );
		this.mapJsonfier         = new JsonfierControl( new MapJsonfier() );
		this.enumerationJsonfier = new JsonfierControl( new EnumerationJsonfier() );

	}
	//****************************************************************************
	public JsonfierSet(JsonfierSet other) {

		this.nullJsonfier        = other.nullJsonfier;
		this.primitiveJsonfier   = other.primitiveJsonfier;
		this.enumJsonfier        = other.enumJsonfier;
		this.stringJsonfier      = other.stringJsonfier;
		this.dateJsonfier        = other.dateJsonfier;
		this.objectJsonfier      = other.objectJsonfier;
		this.arrayJsonfier       = other.arrayJsonfier;
		this.collectionJsonfier  = other.collectionJsonfier;
		this.mapJsonfier         = other.mapJsonfier;
		this.enumerationJsonfier = other.enumerationJsonfier;

	}

	//~ Methods //////////////////////////////////////////////////////////////////
	//****************************************************************************
	/** Chooses correct render depending on given class. It supports the
	 * getInstance() methods above */
	private Jsonfier chooseJsonfier(Class<?> clazz) {

		// If class is primitive
		if ( clazz.isPrimitive() ) {
			return (char.class == clazz) ? this.stringJsonfier : this.primitiveJsonfier;
		}

		// If class is primitive wrapper
		if ( Number.class.isAssignableFrom(clazz)      ) return this.primitiveJsonfier;
		if ( CharSequence.class.isAssignableFrom(clazz)) return this.stringJsonfier;
		if ( Enum.class.isAssignableFrom(clazz)        ) return this.enumJsonfier;
		if ( Boolean.class.isAssignableFrom(clazz)     ) return this.primitiveJsonfier;
		if ( Date.class.isAssignableFrom(clazz)        ) return this.dateJsonfier;
		if ( Character.class.isAssignableFrom(clazz)   ) return this.stringJsonfier;
		if ( Byte.class.isAssignableFrom(clazz)        ) return this.primitiveJsonfier;
		if ( Void.class.isAssignableFrom(clazz)        ) return this.nullJsonfier;

		// If class is a Group of objects
		if ( clazz.isArray()                          ) return this.arrayJsonfier;
		if ( Collection.class.isAssignableFrom(clazz) ) return this.collectionJsonfier;
		if ( Map.class.isAssignableFrom(clazz)        ) return this.mapJsonfier;
		if ( Enumeration.class.isAssignableFrom(clazz)) return this.enumerationJsonfier;

		// Any other type will be handled as object
		return this.objectJsonfier;

	}
	//****************************************************************************
	/** Chooses the correct render depending on the class of the given object */
	public final Jsonfier getJsonfier(Object object) {
		return (object == null)
				? this.nullJsonfier
				: this.chooseJsonfier(object.getClass());
	}
	//****************************************************************************
	/** Chooses the correct render depending on the given class */
	public final Jsonfier getJsonfier(Class<?> clazz) {
		return (clazz == null)
				? this.nullJsonfier
				: this.chooseJsonfier(clazz);
	}
	//****************************************************************************
	/** Chooses the correct render depending on the method's returning type */
	public final Jsonfier getJsonfier(Method method) {
		return (method == null)
				? this.nullJsonfier
				: this.chooseJsonfier( method.getReturnType() );
	}
	//****************************************************************************
	public final JsonfierSet setDateJsonfier(Jsonfier jsonfier) {
		if (jsonfier!=null) {
			this.dateJsonfier = new JsonfierControl(jsonfier);
		}
		return this;
	}
	//****************************************************************************
	public final JsonfierSet setEnumJsonfier(Jsonfier jsonfier) {
		if (jsonfier!=null) {
			this.enumJsonfier = new JsonfierControl(jsonfier);
		}
		return this;
	}
	//****************************************************************************
	@Override
	public Object clone() {
		return new JsonfierSet(this);
	}
	//****************************************************************************

}
